Employees Module

  • Step 1:

    1. Models

    Main model: \odoo\addons\hr\models\hr_employee_base.py

    2. Menu

    E:\odoo\16\server\odoo\addons\hr\views\hr_views.xml

  • Work Locations:

    1. Menu under Configuration

    file : E:\odoo\16\server\odoo\addons\hr\views\hr_views.xml

    
                        <menuitem
                          id="menu_hr_work_location_tree"
                          action="hr_work_location_action"
                          parent="menu_config_employee"
                          sequence="5"
                          groups="group_hr_user"/>
                    

    2. Action window

    hr_work_location_action is id of ir.actions.act_window in E:\odoo\16\server\odoo\addons\hr\views\hr_work_location_views.xml

    
                    <record id="hr_work_location_action" model="ir.actions.act_window">
                        <field name="name">Work Locations1</field>
                        <field name="res_model">hr.work.location</field>
                        <field name="view_mode">tree,form</field>
                    </record>
    
                   
    Work Locations1 is for menu title and page title

    3. Form view

    E:\odoo\16\server\odoo\addons\hr\views\hr_work_location_views.xml

    
                   <record id="hr_work_location_form_view" model="ir.ui.view">
                      <field name="name">hr.work.location.view.form</field>
                      <field name="model">hr.work.location</field>
                      <field name="arch" type="xml">
                          <form string="Work Location">
                              <field name="company_id" invisible="1"/>
                              <sheet>
                                  <group>
                                      <group>
                                          <field name="active" invisible="1" />
                                          <field name="name" />
                                          <field name="address_id" />
                                          <field name="location_number"/>
                                      </group>
                                      <group>
                                          <field name="company_id" groups="base.group_multi_company" />
                                      </group>
                                  </group>
                              </sheet>
                          </form>
                      </field>
                  </record>
    
              

    4. tree view

    E:\odoo\16\server\odoo\addons\hr\views\hr_work_location_views.xml

    
                   <record id="hr_work_location_tree_view" model="ir.ui.view">
                          <field name="name">hr.work.location.view.tree</field>
                          <field name="model">hr.work.location</field>
                          <field name="arch" type="xml">
                              <tree string="Work Location">
                                  <field name="active" invisible="1" />
                                  <field name="name" />
                                  <field name="address_id" />
                                  <field name="company_id" groups="base.group_multi_company" />
                              </tree>
                          </field>
                      </record>
    
              

    5. model

    E:\odoo\16\server\odoo\addons\hr\models\hr_work_location.py

    
              # -*- coding: utf-8 -*-
              # Part of Odoo. See LICENSE file for full copyright and licensing details.
    
              from odoo import fields, models
    
    
              class WorkLocation(models.Model):
                  _name = "hr.work.location"
                  _description = "Work Location"
                  _order = 'name'
    
                  active = fields.Boolean(default=True)
                  name = fields.Char(string="Work Location", required=True)
                  company_id = fields.Many2one('res.company', required=True, default=lambda self: self.env.company)
                  address_id = fields.Many2one('res.partner', required=True, string="Work Address", domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]")
                  location_number = fields.Char()
    
    
              
  • Department:

    1. menu

    File : E:\odoo\16\server\odoo\addons\hr\views\hr_views.xml

    
    
                    <menuitem
                    id="menu_hr_department_tree"
                    action="hr_department_tree_action"
                    parent="menu_config_employee"
                    sequence="4"
                    groups="group_hr_user"/>
    
                   <menuitem
                    id="menu_hr_department_kanban"
                    action="hr_department_kanban_action"
                    parent="menu_hr_root"
                    groups="group_hr_user"/>
    
                  

    2. action window

    File: E:\odoo\16\server\odoo\addons\hr\views\hr_department_views.xml

    ID: hr_department_kanban_action

    
                            <record id="hr_department_kanban_action" model="ir.actions.act_window">
                          <field name="name">Departments</field>
                          <field name="res_model">hr.department</field>
                          <field name="view_mode">kanban,tree,form</field>
                          <field name="search_view_id" ref="view_department_filter"/>
                          <field name="help" type="html">
                            <p class="o_view_nocontent_smiling_face">
                              Create a new department
                            </p><p>
                              Odoo's department structure is used to manage all documents
                              related to employees by departments: expenses, timesheets,
                              time off, recruitments, etc.
                            </p>
                          </field>
                      </record>
    
              

    ID: hr_department_tree_action

    
              <record id="hr_department_tree_action" model="ir.actions.act_window">
                <field name="name">Departments</field>
                <field name="res_model">hr.department</field>
                <field name="view_mode">tree,form,kanban</field>
                <field name="search_view_id" ref="view_department_filter"/>
                <field name="help" type="html">
                    <p class="o_view_nocontent_smiling_face">
                        Create a new department
                    </p><p>
                        Odoo's department structure is used to manage all documents
                        related to employees by departments: expenses, timesheets,
                        leaves, recruitments, etc.
                    </p>
                </field>
            </record>
    
    

    3. form view

    
              <record id="view_department_form" model="ir.ui.view">
                <field name="name">hr.department.form</field>
                <field name="model">hr.department</field>
                <field name="arch" type="xml">
                    <form string="department">
                        <field name="company_id" invisible="1"/>
                        <sheet>
                            <div class="oe_button_box" name="button_box">
                                <button class="oe_stat_button" type="action" name="%(hr.act_employee_from_department)d" icon="fa-users">
                                    <field string="Employees" name="total_employee" widget="statinfo"/>
                                </button>
                                <button class="oe_stat_button" type="object" name="action_plan_from_department" icon="fa-list-ul">
                                    <field string="Plans" name="plans_count" widget="statinfo"/>
                                </button>
                            </div>
                            <widget name="web_ribbon" title="Archived" bg_color="bg-danger" attrs="{'invisible': [('active', '=', True)]}"/>
                            <field name="active" invisible="1"/>
                            <group col="4">
                                <field name="name"/>
                                <field name="manager_id"/>
                                <field name="parent_id"/>
                                <field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
                            </group>
                        </sheet>
                        <div class="oe_chatter">
                            <field name="message_follower_ids" groups="base.group_user"/>
                            <field name="message_ids"/>
                        </div>
                    </form>
                </field>
            </record>
    
    
    1. oe_button_box for top buttons 'Employees' & 'Plans'
    2. oe_chatter for right panel

    4. tree view

    
              <record id="view_department_tree" model="ir.ui.view">
                <field name="name">hr.department.tree</field>
                <field name="model">hr.department</field>
                <field name="arch" type="xml">
                    <tree string="Companies" sample="1">
                        <field name="display_name"/>
                        <field name="company_id" groups="base.group_multi_company"/>
                        <field name="manager_id"/>
                        <field name="total_employee" string="Employees"/>
                        <field name="parent_id"/>
                    </tree>
                </field>
            </record>
    
    

    5. Kanban view

    
            <record id="hr_department_view_kanban" model="ir.ui.view" >
                <field name="name">hr.department.kanban</field>
                <field name="model">hr.department</field>
                <field name="arch" type="xml">
                    <kanban class="oe_background_grey o_kanban_dashboard o_hr_department_kanban o_kanban_small_column" sample="1">
                        <field name="name"/>
                        <field name="company_id"/>
                        <field name="manager_id"/>
                        <field name="color"/>
                        <field name="total_employee"/>
                        <templates>
                            <t t-name="kanban-box">
                                <div t-attf-class="#{!selection_mode ? kanban_color(record.color.raw_value) : ''}">
                                    <div t-attf-class="o_kanban_card_header">
                                        <div class="o_kanban_card_header_title">
                                            <div class="o_primary"><a type="edit"><field name="name"/></a></div>
                                            <div class="o_secondary" groups="base.group_multi_company">
                                                <small>
                                                    <i class="fa fa-building-o" role="img" aria-label="Company" title="Company"/> <field name="company_id"/>
                                                </small>
                                            </div>
                                        </div>
                                        <div class="o_kanban_manage_button_section" t-if="!selection_mode">
                                            <a class="o_kanban_manage_toggle_button" href="#"><i class="fa fa-ellipsis-v" role="img" aria-label="Manage" title="Manage"/></a>
                                        </div>
                                    </div>
                                    <div class="container o_kanban_card_content" t-if="!selection_mode">
                                        <div class="row o_kanban_card_upper_content">
                                            <div class="col-6 o_kanban_primary_left">
                                                <button class="btn btn-primary" name="%(act_employee_from_department)d" type="action">
                                                    <t t-out="record.total_employee.raw_value"/> Employees
                                                </button>
                                            </div>
                                            <div class="col-6 o_kanban_primary_right">
                                            </div>
                                        </div>
                                        <div class="o_kanban_card_lower_content"
                                             style="justify-content: end">
                                            <!-- placeholder for bottom content -->
                                        </div>
                                    </div>
                                    <div class="o_kanban_card_manage_pane dropdown-menu" role="menu">
                                        <div class="o_kanban_card_manage_section">
                                            <div role="menuitem" class="o_kanban_manage_reports">
                                                <div class="o_kanban_card_manage_title ps-4 pb-1">
                                                    <span class="fw-bolder">Reporting</span>
                                                </div>
                                            </div>
                                        </div>
                                        <a t-if="widget.editable" role="menuitem" class="dropdown-item" type="edit">Configuration</a>
                                        <ul t-if="widget.editable" class="oe_kanban_colorpicker" data-field="color" role="menu"/>
                                    </div>
                                </div>
                            </t>
                        </templates>
                    </kanban>
                </field>
            </record>
    
    

    6. fiter option

    
              <record id="view_department_filter" model="ir.ui.view">
                <field name="name">hr.department.search</field>
                <field name="model">hr.department</field>
                <field name="arch" type="xml">
                    <search string="Departments">
                        <field name="name" string="Department"/>
                        <field name="manager_id" />
                        <filter string="Unread Messages" name="message_needaction" domain="[('message_needaction','=',True)]"/>
                        <separator/>
                        <filter string="Archived" name="inactive" domain="[('active','=',False)]"/>
                    </search>
                 </field>
            </record>
    
    
    the id view_department_filter is called in window action

    7. Model

    
    
    from odoo import api, fields, models, _
    from odoo.exceptions import ValidationError
    
    
    class Department(models.Model):
        _name = "hr.department"
        _description = "Department"
        _inherit = ['mail.thread']
        _order = "name"
        _rec_name = 'complete_name'
        _parent_store = True
    
        name = fields.Char('Department Name', required=True)
        complete_name = fields.Char('Complete Name', compute='_compute_complete_name', recursive=True, store=True)
        active = fields.Boolean('Active', default=True)
        company_id = fields.Many2one('res.company', string='Company', index=True, default=lambda self: self.env.company)
        parent_id = fields.Many2one('hr.department', string='Parent Department', index=True, domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]")
        child_ids = fields.One2many('hr.department', 'parent_id', string='Child Departments')
        manager_id = fields.Many2one('hr.employee', string='Manager', tracking=True, domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]")
        member_ids = fields.One2many('hr.employee', 'department_id', string='Members', readonly=True)
        total_employee = fields.Integer(compute='_compute_total_employee', string='Total Employee')
        jobs_ids = fields.One2many('hr.job', 'department_id', string='Jobs')
        plan_ids = fields.One2many('hr.plan', 'department_id')
        plans_count = fields.Integer(compute='_compute_plan_count')
        note = fields.Text('Note')
        color = fields.Integer('Color Index')
        parent_path = fields.Char(index=True, unaccent=False)
        master_department_id = fields.Many2one(
    
        
  • Employeement Type:

    1. menu

    File : E:\odoo\16\server\odoo\addons\hr\views\hr_views.xml

    
                    <menuitem
                        id="menu_view_hr_contract_type"
                        action="hr_contract_type_action"
                        parent="menu_config_recruitment"
                        sequence="2"
                        groups="group_hr_user"/>
    
                     

    2. window action

    E:\odoo\16\server\odoo\addons\hr\views\hr_contract_type_views.xml

    
                     <record id="hr_contract_type_action" model="ir.actions.act_window">
                            <field name="name">Employment Types</field>
                            <field name="res_model">hr.contract.type</field>
                            <field name="view_mode">tree</field>
                        </record>
    
                    
    view_mode is tree only

    3. tree and form view

    
    
                    <record id="hr_contract_type_view_tree" model="ir.ui.view">
                        <field name="model">hr.contract.type</field>
                        <field name="arch" type="xml">
                            <tree string="Contract Types" editable="bottom">
                                <field name="sequence" widget="handle"/>
                                <field name="name"/>
                            </tree>
                        </field>
                    </record>
    
                    <record id="hr_contract_type_view_form" model="ir.ui.view">
                        <field name="model">hr.contract.type</field>
                        <field name="arch" type="xml">
                            <form>
                                <group>
                                    <group>
                                        <field name="name" />
                                    </group>
                                </group>
                            </form>
                        </field>
                    </record>
    
                

    4. model

    
                from odoo import fields, models
    
    
                class ContractType(models.Model):
                    _name = 'hr.contract.type'
                    _description = 'Contract Type'
                    _order = 'sequence'
    
                    name = fields.Char(required=True, translate=True)
                    sequence = fields.Integer()
    
        
  • Job Positions:

    1. menu

    E:\odoo\16\server\odoo\addons\hr\views\hr_views.xml

    
                  <menuitem
                        id="menu_view_hr_job"
                        action="action_hr_job"
                        parent="menu_config_recruitment"
                        sequence="1"/>
    
        

    2. window action

    E:\odoo\16\server\odoo\addons\hr\views\hr_job_views.xml

    
                <record id="action_hr_job" model="ir.actions.act_window">
                <field name="name">Job Positions</field>
                <field name="res_model">hr.job</field>
                <field name="view_mode">tree,form</field>
                <field name="search_view_id" ref="view_job_filter"/>
                <field name="context">{"search_default_Current":1}</field>
                <field name="help" type="html">
                  <p class="o_view_nocontent_smiling_face">
                    Ready to recruit more efficiently?
                  </p><p>
                    Let's create a job position.
                  </p>
                </field>
            </record>
    
        

    3. tree and kanban view

    
        <record id="view_hr_job_tree" model="ir.ui.view">
                <field name="name">hr.job.tree</field>
                <field name="model">hr.job</field>
                <field name="arch" type="xml">
                    <tree string="Job" sample="1">
                        <field name="sequence" widget="handle"/>
                        <field name="name"/>
                        <field name="department_id"/>
                        <field name="no_of_recruitment"/>
                        <field name="no_of_employee" optional="hide"/>
                        <field name="expected_employees" optional="hide"/>
                        <field name="no_of_hired_employee" optional="hide"/>
                        <field name="message_needaction" invisible="1"/>
                        <field name="company_id" groups="base.group_multi_company" optional="hide"/>
                    </tree>
                </field>
            </record>
    
            <record id="hr_job_view_kanban" model="ir.ui.view">
                <field name="name">hr.job.kanban</field>
                <field name="model">hr.job</field>
                <field name="arch" type="xml">
                    <kanban class="o_kanban_mobile" sample="1">
                        <templates>
                            <t t-name="kanban-box">
                                <div class="oe_kanban_global_click">
                                    <div>
                                        <strong><field name="name"/></strong>
                                    </div>
                                    <div>
                                        <span><field name="department_id"/>&amp;nbsp;</span>
                                    </div>
                                    <div t-if="!selection_mode">
                                        <span>Vacancies : <field name="expected_employees"/></span>
                                    </div>
                                </div>
                            </t>
                        </templates>
                    </kanban>
                </field>
            </record>
    
        

    4. Form view

    
                <record id="view_hr_job_form" model="ir.ui.view">
                <field name="name">hr.job.form</field>
                <field name="model">hr.job</field>
                <field name="arch" type="xml">
                    <form string="Job">
                        <field name="active" invisible="1"/>
                        <field name="company_id" invisible="1"/>
                        <sheet>
                            <div class="oe_button_box" name="button_box"/>
                            <div class="oe_title">
                                <label for="name"/>
                                <h1><field name="name" placeholder="e.g. Sales Manager"/></h1>
                            </div>
                            <notebook>
                                <page string="Recruitment" name="recruitment_page">
                                    <group>
                                        <group name="recruitment">
                                            <field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
                                            <field name="department_id"/>
                                            <field name="contract_type_id"/>
                                        </group>
                                        <group name="recruitment2">
                                            <label for="no_of_recruitment"/>
                                            <div class="o_row" name="recruitment_target">
                                                <field name="no_of_recruitment" class="col-3 ps-0"/>
                                                <span class="ps-1">new Employees</span>
                                            </div>
                                        </group>
                                    </group>
                                </page>
                                <page string="Job Summary" name="job_description_page">
                                    <field name="description" options="{'collaborative': true}"/>
                                </page>
                            </notebook>
                        </sheet>
                        <div class="oe_chatter">
                            <field name="message_follower_ids" options="{'open_attachments': True}"/>
                            <field name="message_ids"/>
                        </div>
                    </form>
                </field>
            </record>
    
        
    notebook is for tab view

    5. model

    
            
    from odoo import api, fields, models, _
    
    
    class Job(models.Model):
    
        _name = "hr.job"
        _description = "Job Position"
        _inherit = ['mail.thread']
        _order = 'sequence'
    
        active = fields.Boolean(default=True)
        name = fields.Char(string='Job Position', required=True, index='trigram', translate=True)
        sequence = fields.Integer(default=10)
        expected_employees = fields.Integer(compute='_compute_employees', string='Total Forecasted Employees', store=True,
            help='Expected number of employees for this job position after new recruitment.')
        no_of_employee = fields.Integer(compute='_compute_employees', string="Current Number of Employees", store=True,
            help='Number of employees currently occupying this job position.')
        no_of_recruitment = fields.Integer(string='Target', copy=False,
            help='Number of new employees you expect to recruit.', default=1)
        no_of_hired_employee = fields.Integer(string='Hired Employees', copy=False,
            help='Number of hired employees for this job position during recruitment phase.')
        employee_ids = fields.One2many('hr.employee', 'job_id', string='Employees', groups='base.group_user')
        description = fields.Html(string='Job Description')
        requirements = fields.Text('Requirements')
        department_id = fields.Many2one('hr.department', string='Department', domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]")
        company_id = fields.Many2one('res.company', string='Company', default=lambda self: self.env.company)
        contract_type_id = fields.Many2one('hr.contract.type', string='Employment Type')